home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2 Examples.sit / Raven 1.2 Examples / Quill / Source / ViewContainer.cpp < prev    next >
Text File  |  1997-09-03  |  54KB  |  2,066 lines

  1. /*
  2.  *  File:       ViewContainer.h
  3.  *  Summary:       A view containing the panes to be edited.
  4.  *  Written by: Jesse Jones
  5.  *
  6.  *  Copyright ゥ 1996-1997 Jesse Jones. 
  7.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  8.  *
  9.  *  Change History (most recent first):    
  10.  *
  11.  *         <4>     8/12/97    JDJ        Added context menus.
  12.  *         <3>     4/06/97    JDJ        Updated for new style TSubPaneIterator.
  13.  *         <2>     4/06/97    JDJ        Overrides HandleMouseDown and co to prevent
  14.  *                                    mouse events from reaching sub panes.
  15.  *         <1>     8/26/96    JDJ        Created
  16.  */
  17.  
  18. #include "ViewContainer.h"
  19.  
  20. #include <Algorithm.h>
  21. #include <List.h>
  22. #include <Map.h>
  23. #include <ToolUtils.h>
  24. #include <Vector.h>
  25.  
  26. #include <ZApplication.h>
  27. #include <ZAttributes.h>
  28. #include <ZCommands.h>
  29. #include <ZContextMenu.h>
  30. #include <ZDragSession.h>
  31. #include <ZHandleStream.h>
  32. #include <ZInput.h>
  33. #include <ZLocker.h>
  34. #include <ZMiscUtils.h>
  35. #include <ZPaneTrackers.h>
  36. #include <ZQDShapes.h>
  37. #include <ZQuickDrawUtils.h>
  38. #include <ZScrap.h>
  39. #include <ZStateBroadcaster.h>
  40. #include <ZStringUtils.h>
  41. #include <ZUndoMgr.h>
  42. #include <ZWindow.h>
  43.  
  44. #include "Constants.h"
  45. #include "Document.h"
  46. #include "GridSizeDialog.h"
  47. #include "PaneEditDialog.h"
  48. #include "ViewCommands.h"
  49. #include "ViewDecorations.h"
  50. #include "ViewTrackers.h"
  51. #include "ViewWindow.h"
  52.  
  53.  
  54. __MSL_FIX_ITERATORS__(TPane* const);
  55.  
  56. //-----------------------------------
  57. //    Misc Commands
  58. //
  59. const short kSpaceKeyCode = 0x31;
  60.     
  61.  
  62. //-----------------------------------
  63. //    Menu Commands
  64. //
  65. const MenuCommand kShowGridCmd           = "Show Grid";
  66. const MenuCommand kShowPaneNamesCmd      = "Show Pane Names";
  67. const MenuCommand kShowClassNamesCmd     = "Show Class Names";
  68. const MenuCommand kShowPaneEdgesCmd      = "Show Pane Edges";
  69.  
  70. const MenuCommand kSnapToGridCmd         = "Snap to Grid";
  71. const MenuCommand kEditGridCmd           = "Edit Grid";
  72.  
  73. const MenuCommand kAlignLeftCmd           = "Align Left";
  74. const MenuCommand kAlignRightCmd          = "Align Right";
  75. const MenuCommand kAlignTopCmd            = "Align Top";
  76. const MenuCommand kAlignBottomCmd         = "Align Bottom";
  77.  
  78.  
  79. // ===================================================================================
  80. //    Helper Functions
  81. // ===================================================================================
  82.  
  83. //---------------------------------------------------------------
  84. //
  85. // GetGridSize
  86. //
  87. //---------------------------------------------------------------
  88. static bool GetGridSize(TSize* size) 
  89. {
  90.     bool got = false;
  91.     
  92.     TSize newSize = *size;
  93.     
  94.     if (GetShort(LoadAppString("Grid Width"), 4, &newSize.width, 64)) {
  95.         if (GetShort(LoadAppString("Grid Height"), 4, &newSize.height, 64)) {
  96.             *size = newSize;
  97.             got = true;
  98.         }
  99.     }
  100.     
  101.     return got;
  102. }
  103.  
  104. #pragma mark -
  105.  
  106. // ===================================================================================
  107. //    class CTabBehavior
  108. // ===================================================================================
  109. class CTabBehavior : public TBehavior<TKeyEvent> {
  110.  
  111.     typedef TBehavior<TKeyEvent> Inherited;
  112.  
  113. //-----------------------------------
  114. //    Initialization/Destruction
  115. //
  116. public:
  117.     virtual             ~CTabBehavior();
  118.     
  119.                         CTabBehavior();
  120.  
  121. //-----------------------------------
  122. //    TBehavior API 
  123. //
  124. protected:
  125.     virtual bool         OnExecute(TKeyEvent& event);
  126.  
  127.     virtual void         OnAttached(MBehaviorableBase* owner);
  128.  
  129. //-----------------------------------
  130. //    Types 
  131. //
  132. protected:
  133.     typedef vector<TPane*, allocator<TPane*> > PaneList;
  134.  
  135. //-----------------------------------
  136. //    Internal API 
  137. //
  138. public:
  139.     virtual void         RotateTarget(bool forward = true);
  140.     
  141. protected:
  142.     virtual PaneList*     CreateTargetList(TPane* target);
  143.  
  144. //-----------------------------------
  145. //    Member data 
  146. //
  147. protected:
  148.     CViewContainer*    mContainer;
  149. };
  150.  
  151. //---------------------------------------------------------------
  152. //
  153. // CTabBehavior::~CTabBehavior
  154. //
  155. //---------------------------------------------------------------
  156. CTabBehavior::~CTabBehavior()
  157. {
  158. }
  159.  
  160.  
  161. //---------------------------------------------------------------
  162. //
  163. // CTabBehavior::CTabBehavior
  164. //
  165. //---------------------------------------------------------------
  166. CTabBehavior::CTabBehavior() : TBehavior<TKeyEvent>("CTabBehavior", kNonPersistant)
  167. {
  168.     mContainer = nil;
  169. }
  170.  
  171.  
  172. //---------------------------------------------------------------
  173. //
  174. // CTabBehavior::OnAttached
  175. //
  176. //---------------------------------------------------------------
  177. void CTabBehavior::OnAttached(MBehaviorableBase* owner)
  178. {
  179.     Inherited::OnAttached(owner);
  180.     
  181.     mContainer = dynamic_cast<CViewContainer*>(owner);
  182.     ASSERT(mContainer != nil);
  183. }
  184.  
  185.  
  186. //---------------------------------------------------------------
  187. //
  188. // CTabBehavior::OnExecute
  189. //
  190. //---------------------------------------------------------------
  191. bool CTabBehavior::OnExecute(TKeyEvent& event)
  192. {
  193.     bool handled = false;
  194.     
  195.     if (event.WasKeyDown() && event.GetChar() == kTabChar) {
  196.         this->RotateTarget(!event.WasShiftKeyDown());
  197.         handled = true;
  198.     }
  199.     
  200.     return handled;
  201. }
  202.  
  203.  
  204. //---------------------------------------------------------------
  205. //
  206. // CTabBehavior::RotateTarget
  207. //
  208. //---------------------------------------------------------------
  209. void CTabBehavior::RotateTarget(bool forward)
  210. {
  211.     try {    
  212.         // Find the first selected pane.
  213.         TPane* target = nil;
  214.         TSubPaneIterator iter = mContainer->begin(kRecursive);
  215.         while (iter != mContainer->end() && target == nil) {
  216.             TPane* subPane = *iter;
  217.             ++iter;
  218.             
  219.             if (mContainer->IsSelected(subPane))
  220.                 target = subPane;
  221.         }
  222.     
  223.         // Get a list of the panes to switch among.
  224.         TAutoPtr<PaneList> panes(this->CreateTargetList(target));                    
  225.         long count = panes->size();
  226.  
  227.         // Find out the index of the selected pane.
  228.         PaneList::iterator paneIter = find(panes->begin(), panes->end(), target);
  229.         long targetIndex = paneIter - panes->begin();
  230.                         
  231.         TPane* newTarget = nil;
  232.         
  233.         // If there isn't a selected pane make the first pane the target.
  234.         if (target == nil && count > 0)
  235.             if (forward)
  236.                 newTarget = panes->at(0);
  237.             else
  238.                 newTarget = panes->at(count-1);
  239.             
  240.         // If a subPane has the target select the next subPane.
  241.         else if (target != nil && targetIndex >= 0 && count > 1)
  242.             if (forward)
  243.                 if (targetIndex+1 < count)
  244.                     newTarget = panes->at(targetIndex+1);
  245.                 else
  246.                     newTarget = panes->at(0);
  247.             else
  248.                 if (targetIndex > 0)
  249.                     newTarget = panes->at(targetIndex-1);
  250.                 else
  251.                     newTarget = panes->at(count-1);
  252.         
  253.         // If a subPane has the target, but there isn't another
  254.         // subPane that can become the target don't change the
  255.         // target.
  256.         else if (target != nil && targetIndex >= 0 && count == 1)
  257.             newTarget = target;        
  258.         
  259.         // Change the target. 
  260.         if (newTarget != target)
  261.             mContainer->Select(newTarget);
  262.                 
  263.     } catch (const TBaseException& e) {
  264.         ReportError(LoadAppString("Couldn't switch to the next pane"), e);
  265.     
  266.     } catch(...) {
  267.         ReportError(LoadAppString("Couldn't switch to the next pane"), LoadAppString("Unknown Error"));
  268.     }
  269. }
  270.  
  271.     
  272. //---------------------------------------------------------------
  273. //
  274. // CTabBehavior::CreateTargetList
  275. //
  276. //---------------------------------------------------------------
  277. CTabBehavior::PaneList* CTabBehavior::CreateTargetList(TPane* target)
  278. {
  279.     PaneList* panes = new PaneList;
  280.     
  281.     TView* view = target != nil ? target->GetSuperView() : mContainer;
  282.         
  283.     // Put all of visible subPanes of view in the list.
  284.     TSubPaneIterator iter = view->begin();
  285.     while (iter != view->end()) {
  286.         TPane* subPane = *iter;
  287.         ++iter;
  288.         
  289.         if (subPane->IsVisible())
  290.             panes->push_back(subPane);
  291.     }
  292.     
  293.     return panes;
  294. }
  295.  
  296. #pragma mark -
  297.  
  298. // ===================================================================================
  299. //    struct SResourceID
  300. // ===================================================================================
  301. struct SResourceID {
  302.     ResType    type;
  303.     ResID    id;
  304.     
  305.             SResourceID()                                {type = '????'; id = 0;}
  306.     
  307.             SResourceID(ResType t, ResID i)                {type = t; id = i;}
  308.     
  309.     bool    operator==(const SResourceID& rhs) const    {return type == rhs.type && id == rhs.id;}
  310.  
  311.     bool    operator<(const SResourceID& rhs) const        {return type < rhs.type || (type == rhs.type && id < rhs.id);}
  312. };
  313.  
  314.  
  315. // ===================================================================================
  316. //    class CViewContainer
  317. // ===================================================================================
  318.  
  319. static TReanimatorRegister<CViewContainer> sContainerRegistrar;
  320.  
  321. typedef map<SResourceID, CViewContainer*, less<SResourceID>, allocator<CViewContainer*> > ContainerMap;
  322.  
  323. static ContainerMap sContainers;
  324.  
  325. typedef pair<const SResourceID, CViewContainer*> ContainerEntry;
  326.  
  327. //---------------------------------------------------------------
  328. //
  329. // CViewContainer::~CViewContainer
  330. //
  331. //---------------------------------------------------------------
  332. CViewContainer::~CViewContainer()
  333. {
  334.     if (mType != '????')
  335.         ASSERT(sContainers.count(SResourceID(mType, mRsrcID)) == 1);
  336.     
  337.     this->UpdateResource();
  338.     
  339.     if (mType != '????')
  340.         sContainers.erase(SResourceID(mType, mRsrcID));
  341.  
  342.     if (mSuperView != nil)                        // do this here to maintain CViewWindow's invariant
  343.         mSuperView->RemoveSubPane(this);
  344.         
  345.     if (mDoc != nil)
  346.         mDoc->RemoveReference();
  347. }
  348.  
  349.  
  350. //---------------------------------------------------------------
  351. //
  352. // CViewContainer::CViewContainer (TWindow*)
  353. //
  354. //---------------------------------------------------------------
  355. CViewContainer::CViewContainer(TWindow* wind) : TCachedView("CViewContainer", nil, wind->GetExtent()), MCommander(wind)
  356. {
  357.     ASSERT(wind != nil);
  358.     
  359.     mBinding.left   = true;
  360.     mBinding.right  = true;
  361.     mBinding.top    = true;
  362.     mBinding.bottom = true;
  363.         
  364.     wind->AddSubPane(this);                        // do this here so we're the right type
  365.     
  366.     mDoc      = nil;
  367.     mRsrcMap  = nil;
  368.     mType     = '????';
  369.     mRsrcID   = 0;
  370.     mSettingUp = false;
  371.     
  372.     mSnapToGrid = true;
  373.     mShowGrid   = true;
  374.     mGridSize   = TSize(10, 10);
  375.     
  376.     mShowPaneNames  = false;
  377.     mShowClassNames = false;
  378.     mShowPaneEdges  = true;
  379.         
  380.     wind->SetLatentTarget(this);
  381.  
  382.     MCommander::AddBehaviorToFront(new CTabBehavior);
  383. }
  384.  
  385.  
  386. //---------------------------------------------------------------
  387. //
  388. // CViewContainer::CViewContainer (TWindow*, CResourceMap*, ResID)
  389. //
  390. //---------------------------------------------------------------
  391. CViewContainer::CViewContainer(TWindow* wind, CResourceMap*    rsrcMap, ResID id) : TCachedView("CViewContainer", nil, wind->GetExtent()), MCommander(wind)
  392. {
  393.     ASSERT(wind != nil);
  394.     ASSERT(rsrcMap != nil);
  395.     ASSERT(sContainers.count(SResourceID(rsrcMap->GetType(), id)) == 0);
  396.     
  397.     mBinding.left   = true;
  398.     mBinding.right  = true;
  399.     mBinding.top    = true;
  400.     mBinding.bottom = true;
  401.         
  402.     wind->AddSubPane(this);                        // do this here so we're the right type
  403.     
  404.     mDoc = dynamic_cast<CDocument*>(wind->GetSuperCommander());
  405.     ASSERT(mDoc != nil);
  406.     mDoc->AddReference();
  407.     
  408.     mRsrcMap  = rsrcMap;
  409.     mType     = rsrcMap->GetType();
  410.     mRsrcID   = id;
  411.     mSettingUp = false;
  412.     
  413.     mSnapToGrid = true;
  414.     mShowGrid   = true;
  415.     mGridSize   = TSize(10, 10);
  416.     
  417.     mShowPaneNames  = false;
  418.     mShowClassNames = false;
  419.     mShowPaneEdges  = true;
  420.         
  421.     THandle data = mRsrcMap->GetResourceData(mRsrcID);
  422.     if (data.GetSize() > 0 && dynamic_cast<CViewWindow*>(wind) != nil) {
  423.         TInHandleStream stream(data);    
  424.  
  425.         mSettingUp = true;
  426.  
  427.         TPane* pane = this->CreatePane(stream, this);
  428.         this->DoStreamExtrasIn(stream);
  429.         this->DecoratePane(pane);
  430.                 
  431.         mSettingUp = false;
  432.  
  433.         wind->SetSize(pane->GetSize());
  434.         pane->SetLocation(kZeroPt);
  435.     }
  436.  
  437.     sContainers.insert(ContainerEntry(SResourceID(mType, mRsrcID), this));
  438.  
  439.     mRsrcMap->AddListener(this);
  440.  
  441.     wind->SetLatentTarget(this);
  442.  
  443.     MCommander::AddBehaviorToFront(new CTabBehavior);
  444. }
  445.  
  446.  
  447. //---------------------------------------------------------------
  448. //
  449. // CViewContainer::Create                                [static]
  450. //
  451. //---------------------------------------------------------------
  452. MReanimatable* CViewContainer::Create(MReanimatable* parent)
  453. {
  454.     TView* view = dynamic_cast<TView*>(parent);
  455.  
  456.     if (view != nil && view->HasAttribute("Editing"))
  457.         return new CViewContainer(dynamic_cast<TWindow*>(parent));
  458.     else
  459.         return new TView("????", dynamic_cast<TView*>(parent), TRect(0, 0, 100, 100));
  460. }
  461.  
  462.  
  463. //---------------------------------------------------------------
  464. //
  465. // CViewContainer::SetResourceID
  466. //
  467. //---------------------------------------------------------------
  468. void CViewContainer::SetResourceID(CResourceMap* rsrcMap, ResID id)
  469. {
  470.     ASSERT(rsrcMap != nil);
  471.     ASSERT(mRsrcMap == nil);
  472.     ASSERT(sContainers.count(SResourceID(rsrcMap->GetType(), id)) == 0);
  473.     
  474.     mRsrcMap = rsrcMap;
  475.     mType    = rsrcMap->GetType();
  476.     mRsrcID  = id;
  477.         
  478.     sContainers.insert(ContainerEntry(SResourceID(mType, mRsrcID), this));
  479.  
  480.     mRsrcMap->AddListener(this);
  481. }
  482.  
  483.  
  484. //---------------------------------------------------------------
  485. //
  486. // CViewContainer::GetContainer                            [static]
  487. //
  488. //---------------------------------------------------------------
  489. CViewContainer* CViewContainer::GetContainer(ResType type, ResID id)
  490. {
  491.     CViewContainer* container = nil;
  492.     
  493.     ContainerMap::iterator iter = sContainers.find(SResourceID(type, id));
  494.     if (iter != sContainers.end())
  495.         container = (*iter).second;
  496.         
  497.     return container;
  498. }
  499.  
  500.  
  501. //---------------------------------------------------------------
  502. //
  503. // CViewContainer::UpdateResource
  504. //
  505. //---------------------------------------------------------------
  506. void CViewContainer::UpdateResource()        
  507. {
  508.     PRECONDITION(this->GetSuperView() != nil);
  509.  
  510.     if (mRsrcMap != nil && mRsrcMap->HasResource(mRsrcID)) {
  511.         THandle data = mRsrcMap->GetResourceData(mRsrcID);
  512.         data.Detach();
  513.         data.SetSize(0);
  514.             
  515.         {
  516.         TOutHandleStream stream(data);                
  517.             TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
  518.             if (dynamic_cast<CViewWindow*>(window) != nil) {
  519.                 if (mSubPanes->size() == 1) {
  520.                     TPane* pane = mSubPanes->front();
  521.                     
  522.                     pane->Externalize(stream);
  523.                     this->DoStreamExtrasOut(stream);
  524.  
  525.                 } else            
  526.                     ASSERT(mSubPanes->size() == 0);
  527.  
  528.             } else
  529.                 window->Externalize(stream);
  530.         }
  531.         
  532.         mRsrcMap->SetResourceData(mRsrcID, data);
  533.     }
  534.             
  535.     POSTCONDITION(true);
  536. }
  537.  
  538.  
  539. //---------------------------------------------------------------
  540. //
  541. // CViewContainer::HasSelection
  542. //
  543. //---------------------------------------------------------------
  544. bool CViewContainer::HasSelection() const
  545. {
  546.     bool has = false;
  547.     
  548.     TSubPaneIterator iter = this->begin(kRecursive);
  549.     while (iter != this->end() && !has) {
  550.         TPane* pane = *iter;
  551.         ++iter;
  552.         
  553.         has = this->IsSelected(pane);
  554.     }
  555.     
  556.     return has;
  557. }
  558.  
  559.  
  560. //---------------------------------------------------------------
  561. //
  562. // CViewContainer::HasMoreThanOneSelection
  563. //
  564. //---------------------------------------------------------------
  565. bool CViewContainer::HasMoreThanOneSelection() const
  566. {
  567.     long count = 0;
  568.     
  569.     TSubPaneIterator iter = this->begin(kRecursive);
  570.     while (iter != this->end() && count < 2) {
  571.         TPane* pane = *iter;
  572.         ++iter;
  573.         
  574.         if (this->IsSelected(pane))
  575.             count++;
  576.     }
  577.     
  578.     return count == 2;
  579. }
  580.  
  581.  
  582. //---------------------------------------------------------------
  583. //
  584. // CViewContainer::IsSelected
  585. //
  586. //---------------------------------------------------------------
  587. bool CViewContainer::IsSelected(TPane* pane) const
  588. {
  589.     ASSERT(pane != nil);
  590.     
  591.     return pane->FindAdorner("CHandleAdorner") != nil;
  592. }
  593.  
  594.  
  595. //---------------------------------------------------------------
  596. //
  597. // CViewContainer::Select
  598. //
  599. //---------------------------------------------------------------
  600. void CViewContainer::Select(TPane* pane, bool extend, bool toggle)
  601. {
  602.     PRECONDITION(pane == nil || this->IsSubPane(pane));
  603.     ASSERT(pane != this);
  604.     
  605.     if (extend) {
  606.         if (pane != nil && !this->IsSelected(pane) && !this->ParentIsSelected(pane))
  607.             this->DoSelect(pane);
  608.         
  609.     } else if (toggle) {
  610.         if (pane != nil) {
  611.             if (this->IsSelected(pane))
  612.                 this->DoDeselect(pane);
  613.             else if (!this->ParentIsSelected(pane))
  614.                 this->DoSelect(pane);
  615.         }
  616.         
  617.     } else {
  618.         TSubPaneIterator iter = this->begin(kRecursive);
  619.         while (iter != this->end()) {
  620.             TPane* subPane = *iter;
  621.             ++iter;
  622.             
  623.             if (this->IsSelected(subPane) && subPane != pane)
  624.                 this->DoDeselect(subPane);
  625.         }
  626.  
  627.         if (pane != nil && !this->IsSelected(pane))
  628.             this->DoSelect(pane);
  629.     }
  630.  
  631.     POSTCONDITION(true);
  632. }
  633.  
  634.  
  635. //---------------------------------------------------------------
  636. //
  637. // CViewContainer::HandleMouseDown
  638. //
  639. //---------------------------------------------------------------
  640. bool CViewContainer::HandleMouseDown(const TMouseEvent& event)
  641. {
  642.     return TPane::HandleMouseDown(event);    // don't give subPane's a chance to handle the event
  643. }
  644.  
  645.     
  646. //---------------------------------------------------------------
  647. //
  648. // CViewContainer::HandleMouseUp
  649. //
  650. //---------------------------------------------------------------
  651. bool CViewContainer::HandleMouseUp(const TMouseEvent& event)
  652. {
  653.     return TPane::HandleMouseUp(event);    // don't give subPane's a chance to handle the event
  654. }
  655.  
  656.         
  657. //---------------------------------------------------------------
  658. //
  659. // CViewContainer::HandleContextMenu
  660. //
  661. //---------------------------------------------------------------
  662. bool CViewContainer::HandleContextMenu(const TMouseEvent& event)
  663. {
  664.     return TPane::HandleContextMenu(event);    // don't give subPane's a chance to handle the event
  665. }
  666.  
  667.         
  668. //---------------------------------------------------------------
  669. //
  670. // CViewContainer::HandleAdjustCursor
  671. //
  672. //---------------------------------------------------------------
  673. bool CViewContainer::HandleAdjustCursor(const TEvent& event)
  674. {
  675.     return TPane::HandleAdjustCursor(event);    // don't give subPane's a chance to handle the event
  676. }
  677.  
  678. #pragma mark ハ
  679.  
  680. //---------------------------------------------------------------
  681. //
  682. // CViewContainer::Invariant
  683. //
  684. //---------------------------------------------------------------
  685. void CViewContainer::Invariant() const
  686. {
  687.     Inherited::Invariant();
  688.     
  689.     ASSERT(mGridSize.width > 0);
  690.     ASSERT(mGridSize.height > 0);
  691.     
  692.     // If we're in a CViewWindow then we're editing a pane instead
  693.     // of a window and the CViewWindow can have only one subPane.
  694.     TView* superView = this->GetSuperView();
  695.     if (dynamic_cast<CViewWindow*>(superView) != nil)
  696.         ASSERT(mSubPanes->size() <= 1);
  697.         
  698.     // View should be in a window and the super commander should
  699.     // be the window.
  700.     if (superView != nil) {
  701.         TWindow* window = dynamic_cast<TWindow*>(superView);
  702.         ASSERT(window != nil);
  703.         ASSERT(this->GetSuperCommander() == window);
  704.     }
  705.     
  706.     // 'this' should not have the edit adorners
  707.     ASSERT(TView::FindAdorner("COutlineAdorner") == nil);    
  708.     ASSERT(TView::FindAdorner("CHandleAdorner") == nil);
  709.     ASSERT(TView::FindAdorner("CPaneNameAdorner") == nil);
  710.     ASSERT(TView::FindAdorner("CClassNameAdorner") == nil);
  711.  
  712.     // For each pane we're editing:
  713. #if DEBUG
  714.     if (gIntenseDebugging && !mSettingUp) {        
  715.         TSubPaneIterator iter = this->begin(kRecursive);
  716.         while (iter != this->end()) {
  717.             TPane* pane = *iter;
  718.             ++iter;
  719.     
  720.             // none of them should have the target
  721.             if (MCommander* commander = dynamic_cast<MCommander*>(pane))
  722.                 ASSERT(!commander->IsTarget());
  723.             
  724.             // make sure they have the right behaviors and adorners            
  725.             if (mShowPaneEdges)
  726.                 ASSERT(pane->FindAdorner("COutlineAdorner") != nil);
  727.                 
  728.             if (mShowPaneNames)
  729.                 ASSERT(pane->FindAdorner("CPaneNameAdorner") != nil);
  730.             
  731.             if (mShowClassNames)
  732.                 ASSERT(pane->FindAdorner("CClassNameAdorner") != nil);
  733.             
  734.             if (this->IsSelected(pane)) {
  735.             
  736.                 // if they're selected they get a few additional behaviors
  737.                 // and adorners
  738.                 ASSERT(pane->FindAdorner("CHandleAdorner") != nil);
  739.  
  740.                 // subPanes of a selected view shouldn't be selected.
  741.                 if (TView* view = dynamic_cast<TView*>(pane)) {
  742.                     TSubPaneIterator iter2 = view->begin(kRecursive);
  743.                     while (iter2 != view->end()) {
  744.                         TPane* subPane = *iter2;
  745.                         ++iter2;
  746.                 
  747.                         ASSERT(!this->IsSelected(subPane));
  748.                     }
  749.                 }
  750.             }
  751.         }
  752.     }
  753. #endif
  754. }
  755.  
  756.  
  757. //---------------------------------------------------------------
  758. //
  759. // CViewContainer::OnDraw
  760. //
  761. //---------------------------------------------------------------
  762. void CViewContainer::OnDraw(TCanvas& canvas, const TRegion& dirtyRgn)
  763. {
  764.     TRegionShape::Fill(canvas, dirtyRgn, kRGBWhite);
  765.     
  766.     if (mShowGrid) {
  767.         TRect extent = this->GetExtent();
  768.         
  769.         SPen pen(kRGBGray);
  770.         GetIndPattern(&pen.pattern, 0, 26);
  771.         
  772.         long h = mGridSize.width;
  773.         while (h < extent.right) {
  774.             TLineShape::Draw(canvas, TPoint(h, extent.top), TPoint(h, extent.bottom), pen);
  775.             h += mGridSize.width;
  776.         }
  777.         
  778.         long v = mGridSize.height;
  779.         while (v < extent.bottom) {
  780.             TLineShape::Draw(canvas, TPoint(extent.left, v), TPoint(extent.right, v), pen);
  781.             v += mGridSize.height;
  782.         }
  783.     }
  784. }
  785.  
  786.  
  787. //---------------------------------------------------------------
  788. //
  789. // CViewContainer::OnMouseDown
  790. //
  791. //---------------------------------------------------------------
  792. bool CViewContainer::OnMouseDown(const TMouseEvent& event)
  793. {
  794.     TPane* pane = this->FindPane(event.GetPosition());
  795.     
  796.     if (event.GetClickCount() == 2) {
  797.         if (pane != nil) {
  798.             if (pane != this)
  799.                 this->Select(pane);
  800.             
  801.             CPaneEditDialog::EditPane(pane);
  802.         }
  803.         
  804.     } else if (event.GetClickCount() == 1) {
  805.         if (event.WasCommandKeyDown()) {
  806.             TTracker* tracker = new TSelectPanesTracker(this, event.GetPosition(), event.WasShiftKeyDown());
  807.             tracker->Post();
  808.             
  809.         } else if (IsKeyDown(kSpaceKeyCode)) {
  810.             this->DoDragWindow(event.GetGlobalPosition());
  811.             
  812.         } else if (pane == this) {
  813.             this->Select(nil);
  814.         
  815.         } else if (pane != nil) {
  816.             if (this->IsSelected(pane) && this->ClickedHandle(pane, event))
  817.                 ;
  818.                 
  819.             else if (::WaitMouseMoved(event.GetGlobalPosition())) {
  820.                 if (!this->IsSelected(pane)) {
  821.                     this->Select(pane, event.WasShiftKeyDown());
  822.                     this->HandleUpdate();
  823.                 }
  824.             
  825.                 this->HandleDragStart(event);
  826.                 
  827.             } else 
  828.                 this->Select(pane, event.WasShiftKeyDown(), event.WasCommandKeyDown());
  829.         }
  830.     }
  831.             
  832.     return kHandled;
  833. }
  834.  
  835.  
  836. //---------------------------------------------------------------
  837. //
  838. // CViewContainer::OnContextMenu
  839. //
  840. //---------------------------------------------------------------
  841. bool CViewContainer::OnContextMenu(const TMouseEvent& event)
  842. {
  843.     TPane* pane = this->FindPane(event.GetPosition());
  844.     if (pane != nil && pane != this && !this->IsSelected(pane)) {
  845.         this->Select(pane);
  846.         this->HandleUpdate();
  847.     }
  848.     
  849.     TContextMenu* popup = new TContextMenu(this, event.GetGlobalPosition(), pane != nil && pane != this ? 319 : 320);
  850.     popup->Post();
  851.     
  852.     return kHandled;
  853. }
  854.  
  855.  
  856. //---------------------------------------------------------------
  857. //
  858. // CViewContainer::OnAdjustCursor
  859. //
  860. //---------------------------------------------------------------
  861. bool CViewContainer::OnAdjustCursor(const TEvent& event)
  862. {
  863.     if (event.WasCommandKeyDown())
  864.         UCursorUtils::SetCursor(kCrossHairCursor);
  865.         
  866.     else if (IsKeyDown(kSpaceKeyCode))
  867.         UCursorUtils::SetCursor(kOpenHandCursor);
  868.  
  869.     else
  870.         UCursorUtils::SetCursor(kArrowCursor);
  871.         
  872.     return kHandled;
  873. }
  874.  
  875.  
  876. //---------------------------------------------------------------
  877. //
  878. // CViewContainer::OnAdjustSubPaneSizes
  879. //
  880. //---------------------------------------------------------------
  881. void CViewContainer::OnAdjustSubPaneSizes(const TPoint& delta, bool redraw)
  882. {
  883.     #pragma unused(delta, redraw)
  884.     
  885.     // do nothing
  886. }
  887.  
  888.  
  889. //---------------------------------------------------------------
  890. //
  891. // CViewContainer::DoStreamExtrasIn
  892. //
  893. //---------------------------------------------------------------
  894. void CViewContainer::DoStreamExtrasIn(TInStream& stream)
  895. {
  896.     try {
  897.         Inherited::DoStreamExtrasIn(stream);
  898.  
  899.         if (this->HasAttribute("Window Frame")) {
  900.             TRectAttribute* frameAttr = dynamic_cast<TRectAttribute*>(this->GetAttribute("Window Frame"));
  901.             TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
  902.             window->SetFrame(frameAttr->GetValue());
  903.             window->ForceOnScreen();
  904.         }
  905.  
  906.         if (this->HasAttribute("Snap To Grid")) {
  907.             TBoolAttribute* snapGridAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Snap To Grid"));
  908.             mSnapToGrid = snapGridAttr->GetValue();
  909.         }
  910.         
  911.         if (this->HasAttribute("Show Grid")) {
  912.             TBoolAttribute* showGridAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Grid"));
  913.             mShowGrid = showGridAttr->GetValue();
  914.         }
  915.         
  916.         if (this->HasAttribute("Grid Size")) {
  917.             TSizeAttribute* gridSizeAttr = dynamic_cast<TSizeAttribute*>(this->GetAttribute("Grid Size"));
  918.             mGridSize = gridSizeAttr->GetValue();
  919.         }
  920.  
  921.         if (this->HasAttribute("Show Pane Names")) {
  922.             TBoolAttribute* paneNameAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Pane Names"));
  923.             mShowPaneNames = paneNameAttr->GetValue();
  924.         }
  925.         
  926.         if (this->HasAttribute("Show Class Names")) {
  927.             TBoolAttribute* classNameAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Class Names"));
  928.             mShowClassNames = classNameAttr->GetValue();
  929.         }
  930.     
  931.         if (this->HasAttribute("Show Pane Edges")) {
  932.             TBoolAttribute* edgesAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Pane Edges"));
  933.             mShowPaneEdges = edgesAttr->GetValue();
  934.         }
  935.     
  936.     } catch (const TBaseException& e) {
  937.         ReportError(LoadAppString("Couldn't read the view's preferences"), e);        
  938.     
  939.     } catch (...) {
  940.         ReportError(LoadAppString("Couldn't read the view's preferences"), LoadAppString("Unknown Error"));
  941.     }
  942. }
  943.  
  944.  
  945. //---------------------------------------------------------------
  946. //
  947. // CViewContainer::DoStreamExtrasOut
  948. //
  949. //---------------------------------------------------------------
  950. void CViewContainer::DoStreamExtrasOut(TOutStream& stream) const
  951. {
  952.     CViewContainer* thisPtr = const_cast<CViewContainer*>(this);
  953.     
  954.     try {
  955.         // Save the window's frame.
  956.         if (!this->HasAttribute("Window Frame"))
  957.             thisPtr->AddAttribute("Window Frame", new TRectAttribute);
  958.         
  959.         TRectAttribute* frameAttr = dynamic_cast<TRectAttribute*>(this->GetAttribute("Window Frame"));
  960.         TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
  961.         frameAttr->SetValue(window->GetFrame());
  962.         
  963.         // Save the snap to grid flag.
  964.         if (!this->HasAttribute("Snap To Grid"))
  965.             thisPtr->AddAttribute("Snap To Grid", new TBoolAttribute);
  966.         
  967.         TBoolAttribute* snapGridAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Snap To Grid"));
  968.         snapGridAttr->SetValue(mSnapToGrid);
  969.         
  970.         // Save the show grid flag.
  971.         if (!this->HasAttribute("Show Grid"))
  972.             thisPtr->AddAttribute("Show Grid", new TBoolAttribute);
  973.         
  974.         TBoolAttribute* showGridAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Grid"));
  975.         showGridAttr->SetValue(mShowGrid);
  976.         
  977.         // Save the grid size.
  978.         if (!this->HasAttribute("Grid Size"))
  979.             thisPtr->AddAttribute("Grid Size", new TSizeAttribute);
  980.         
  981.         TSizeAttribute* gridSizeAttr = dynamic_cast<TSizeAttribute*>(this->GetAttribute("Grid Size"));
  982.         gridSizeAttr->SetValue(mGridSize);
  983.  
  984.         // Save the show pane names flag.
  985.         if (!this->HasAttribute("Show Pane Names"))
  986.             thisPtr->AddAttribute("Show Pane Names", new TBoolAttribute);
  987.         
  988.         TBoolAttribute* paneNameAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Pane Names"));
  989.         paneNameAttr->SetValue(mShowPaneNames);
  990.         
  991.         // Save the show class names flag.
  992.         if (!this->HasAttribute("Show Class Names"))
  993.             thisPtr->AddAttribute("Show Class Names", new TBoolAttribute);
  994.         
  995.         TBoolAttribute* classNameAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Class Names"));
  996.         classNameAttr->SetValue(mShowClassNames);
  997.     
  998.         // Save the show pane edges flag.
  999.         if (!this->HasAttribute("Show Pane Edges"))
  1000.             thisPtr->AddAttribute("Show Pane Edges", new TBoolAttribute);
  1001.         
  1002.         TBoolAttribute* edgesAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Pane Edges"));
  1003.         edgesAttr->SetValue(mShowPaneEdges);
  1004.     
  1005.     } catch (const TBaseException& e) {
  1006.         ReportError(LoadAppString("Couldn't save the view's preferences"), e);
  1007.     
  1008.     } catch (...) {
  1009.         ReportError(LoadAppString("Couldn't save the view's preferences"), LoadAppString("Unknown Error"));
  1010.     }
  1011.     
  1012.     Inherited::DoStreamExtrasOut(stream);
  1013. }
  1014.  
  1015.  
  1016. //---------------------------------------------------------------
  1017. //
  1018. // CViewContainer::OnAddDragData
  1019. //
  1020. //---------------------------------------------------------------
  1021. void CViewContainer::OnAddDragData(TDragSession& session, const TMouseEvent& event)
  1022. {
  1023.     #pragma unused(event)
  1024.     
  1025.     ASSERT(this->HasSelection());
  1026.     
  1027.     bool firstPane = true;
  1028.     
  1029.     TSubPaneIterator iter = this->begin(kRecursive);
  1030.     while (iter != this->end()) {
  1031.         TPane* pane = *iter;
  1032.         ++iter;
  1033.         
  1034.         if (this->IsSelected(pane)) {
  1035.         
  1036.             // add the flavor
  1037.             SResource rsrc(kIndeterminateID);
  1038.             
  1039.             {
  1040.             TOutHandleStream stream(rsrc.data);                
  1041.                 pane->Externalize(stream);
  1042.             }
  1043.  
  1044.             rsrc.AddData(session, (ItemReference) pane, 'View', flavorSenderOnly);
  1045.  
  1046.             // add the drag region
  1047.             TRect dragRect = pane->GetExtent();
  1048.             dragRect = pane->LocalToPort(dragRect);
  1049.             dragRect = pane->PortToGlobal(dragRect);
  1050.  
  1051.             session.AddDragRgn((ItemReference) pane, dragRect);
  1052.         }
  1053.     }
  1054. }
  1055.  
  1056.  
  1057. //---------------------------------------------------------------
  1058. //
  1059. // CViewContainer::OnDragInput
  1060. //
  1061. //---------------------------------------------------------------
  1062. void CViewContainer::OnDragInput(TMouseEvent& event, const TDragSession& session)
  1063. {
  1064.     MConstrainedDragTarget::OnDragInput(event, session);
  1065.     
  1066.     // Snap the first item into place.
  1067.     if (mSnapToGrid) {
  1068.         TPoint mouse = event.GetPosition();
  1069.         
  1070.         TPoint constrain = mouse + msItemOffset;
  1071.         TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
  1072.         constrain -= window->GetFrame()[topLeft];
  1073.         
  1074.         TPoint constrained;
  1075.         constrained.h = ((constrain.h + mGridSize.width/2)/mGridSize.width)*mGridSize.width;
  1076.         constrained.v = ((constrain.v + mGridSize.height/2)/mGridSize.height)*mGridSize.height;
  1077.         
  1078.         TPoint delta = constrained - constrain;
  1079.         
  1080.         event.SetPosition(mouse + delta);
  1081.     }
  1082. }
  1083.  
  1084.  
  1085. //---------------------------------------------------------------
  1086. //
  1087. // CViewContainer::OnGetDragWindow
  1088. //
  1089. //---------------------------------------------------------------
  1090. WindowRef CViewContainer::OnGetDragWindow() const
  1091. {
  1092.     TView* topView = this->GetTopView();
  1093.     TWindow* window = dynamic_cast<TWindow*>(topView);
  1094.  
  1095.     return window->GetWindowRef();
  1096. }
  1097.  
  1098.  
  1099. //---------------------------------------------------------------
  1100. //
  1101. // CViewContainer::OnGetDropRegion
  1102. //
  1103. //---------------------------------------------------------------
  1104. TRegion CViewContainer::OnGetDropRegion()
  1105. {
  1106.     TRect dropRect;
  1107.     
  1108.     dropRect = this->GetExtent();
  1109.     dropRect = this->LocalToPort(dropRect);
  1110.     dropRect = this->PortToGlobal(dropRect);
  1111.  
  1112.     return dropRect;
  1113. }
  1114.  
  1115.  
  1116. //---------------------------------------------------------------
  1117. //
  1118. // CViewContainer::OnGetDropHiliteRegion
  1119. //
  1120. //---------------------------------------------------------------
  1121. TRegion CViewContainer::OnGetDropHiliteRegion(const TDragSession& session)
  1122. {
  1123.     TRect extent = kZeroRect;
  1124.     
  1125.     TView* view = this->FindDropTarget(session);
  1126.     if (view != nil) {
  1127.         extent = view->GetExtent();
  1128.         extent = view->LocalToPort(extent);
  1129.         extent = view->PortToGlobal(extent);
  1130.         
  1131.         msDragLeftTarget = true;
  1132.     }
  1133.             
  1134.     return extent;
  1135. }
  1136.  
  1137.  
  1138. //---------------------------------------------------------------
  1139. //
  1140. // CViewContainer::OnCanAcceptDrag
  1141. //
  1142. //---------------------------------------------------------------
  1143. bool CViewContainer::OnCanAcceptDrag(ItemReference item, const TDragSession& session)
  1144. {
  1145.     bool accept = false;
  1146.     
  1147.     if (session.HasFlavor(item, 'View'))
  1148.         accept = this->FindDropTarget(session) != nil;
  1149.     
  1150.     return accept;
  1151. }
  1152.  
  1153.  
  1154. //---------------------------------------------------------------
  1155. //
  1156. // CViewContainer::OnDragReceive
  1157. //
  1158. //---------------------------------------------------------------
  1159. void CViewContainer::OnDragReceive(const TDragSession& session)
  1160. {
  1161.     // Find the view the mouse was over.
  1162.     TView* view = this->FindDropTarget(session);
  1163.     if (view != nil) {
  1164.     
  1165.         // Get the undo context (we need to do this because the
  1166.         // window may not be the frontmost regular window).
  1167.         TView* topView = this->GetTopView();
  1168.         TWindow* window = dynamic_cast<TWindow*>(topView);
  1169.         TUndoMgr* context = window->GetUndoContext();
  1170.         
  1171.         CAddSubPanesCommand* command = new CAddSubPanesCommand(this, view, context);
  1172.  
  1173.         try {
  1174.             mSettingUp = true;
  1175.  
  1176.             // Drop the panes into the view.
  1177.             long count = session.GetItemCount();
  1178.             for (long index = 0; index < count; index++) {
  1179.                 ItemReference item = session.GetItemReference(index);
  1180.                 
  1181.                 if (session.HasFlavor(item, 'View')) {
  1182.                     TPane* pane = nil;
  1183.                 
  1184.                     {
  1185.                     // create the new pane (some pane classes require
  1186.                     // a port during construction so we'll temporarily
  1187.                     // hook it into the view hierarchy)
  1188.                     SResource rsrc(session, item, 'View');
  1189.  
  1190.                     TInHandleStream stream(rsrc.data);    
  1191.                         pane = this->CreatePane(stream, view);
  1192.                         view->RemoveSubPane(pane);
  1193.                     }
  1194.                     
  1195.                     // find out where it was dropped
  1196.                     TPoint mouse = session.GetItemBounds(item)[topLeft];
  1197.                     mouse = view->GlobalToPort(mouse);
  1198.                     mouse = view->PortToLocal(mouse);
  1199.                     
  1200.                     // move the pane to the correct position (do this 
  1201.                     // here to minimize invalidation)
  1202.                     pane->SetLocation(mouse);
  1203.                     
  1204.                     // add the appropiate adorners and behaviors
  1205.                     this->DecoratePane(pane);
  1206.                     if (!this->IsSelected(pane))
  1207.                         this->DoSelect(pane);        
  1208.                     
  1209.                     // insert the new panes into the view hierarchy
  1210.                     command->AddPane(pane);
  1211.                 }
  1212.             }
  1213.         
  1214.             command->Post();
  1215.  
  1216.         } catch (...) {
  1217.             delete command;
  1218.             throw;
  1219.         }
  1220.     }
  1221.  
  1222.     mSettingUp = false;
  1223. }
  1224.  
  1225.  
  1226. //---------------------------------------------------------------
  1227. //
  1228. // CViewContainer::OnDragMoved
  1229. //
  1230. //---------------------------------------------------------------
  1231. void CViewContainer::OnDragMoved(const TDragSession& session)
  1232. {
  1233.     // Find the view the mouse was over.
  1234.     TView* view = this->FindDropTarget(session);
  1235.     if (view != nil) {
  1236.     
  1237.         // Get the undo context (we need to do this because the
  1238.         // window may not be the frontmost regular window).
  1239.         TView* topView = this->GetTopView();
  1240.         TWindow* window = dynamic_cast<TWindow*>(topView);
  1241.         TUndoMgr* context = window->GetUndoContext();
  1242.         
  1243.         CMovePanesCommand* command = new CMovePanesCommand(this, view, context);
  1244.  
  1245.         try {
  1246.             // Move each pane to its new location.
  1247.             long count = session.GetItemCount();
  1248.             for (long index = 0; index < count; index++) {
  1249.                 ItemReference item = session.GetItemReference(index);
  1250.                 
  1251.                 if (session.HasFlavor(item, 'View')) {
  1252.                 
  1253.                     // find out which pane we're moving
  1254.                     TPane* pane = reinterpret_cast<TPane*>(item);
  1255.                     ASSERT(this->IsSubPane(pane));
  1256.                     
  1257.                     // find out where it was dropped
  1258.                     TPoint globalLoc = session.GetItemBounds(item)[topLeft];
  1259.                     TPoint portLoc   = view->GlobalToPort(globalLoc);
  1260.                     TPoint superLoc  = view->PortToLocal(portLoc);
  1261.                     
  1262.                     // move the pane to the correct position 
  1263.                     command->AddPane(pane, superLoc);
  1264.                 }
  1265.             }
  1266.         
  1267.             command->Post();
  1268.  
  1269.         } catch (...) {
  1270.             delete command;
  1271.             throw;
  1272.         }
  1273.     }
  1274. }
  1275.  
  1276.  
  1277. //---------------------------------------------------------------
  1278. //
  1279. // CViewContainer::OnReanimated
  1280. //
  1281. //---------------------------------------------------------------
  1282. void CViewContainer::OnReanimated()
  1283. {
  1284.     ASSERT(mDoc == nil);
  1285.     
  1286.     Inherited::OnReanimated();
  1287.  
  1288.     TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
  1289.     ASSERT(window != nil);
  1290.     
  1291.     mDoc = dynamic_cast<CDocument*>(window->GetSuperCommander());
  1292.     ASSERT(mDoc != nil);
  1293.     
  1294.     mDoc->AddReference();            // make sure doc isn't deleted before we get a chance to update it
  1295. }
  1296.  
  1297.  
  1298. //---------------------------------------------------------------
  1299. //
  1300. // CViewContainer::OnStreamOut
  1301. //
  1302. // When a window is reanimated a TView is created instead of the
  1303. // CViewContainer. To make this work properly we need to bypass
  1304. // the TCachedView streaming (this is OK since we're just using
  1305. // the system colors). Note that this is only called when editing
  1306. // windows; panes are streamed out directly (see UpdateResource).
  1307. //
  1308. //---------------------------------------------------------------
  1309. void CViewContainer::OnStreamOut(TOutStream& stream) const
  1310. {
  1311.     ASSERT(dynamic_cast<CViewWindow*>(this->GetTopView()) == nil);
  1312.  
  1313.     TView::OnStreamOut(stream);
  1314. }
  1315.  
  1316.  
  1317. //---------------------------------------------------------------
  1318. //
  1319. // CViewContainer::OnStreamIn
  1320. //
  1321. //---------------------------------------------------------------
  1322. void CViewContainer::OnStreamIn(TInStream& stream, long version)
  1323. {
  1324.     ASSERT(dynamic_cast<CViewWindow*>(this->GetTopView()) == nil);
  1325.     
  1326.     mSettingUp = true;                        // ・・・ハshould probably use a stack based class to set this
  1327.  
  1328.     TView::OnStreamIn(stream, version);
  1329.  
  1330.     TSubPaneIterator iter = this->begin();
  1331.     while (iter != this->end()) {
  1332.         TPane* subPane = *iter;
  1333.         ++iter;
  1334.         
  1335.         this->DecoratePane(subPane);
  1336.     }
  1337.     
  1338.     mSettingUp = false;
  1339. }
  1340.  
  1341.  
  1342. //---------------------------------------------------------------
  1343. //
  1344. // CViewContainer::OnBroadcast
  1345. //
  1346. //---------------------------------------------------------------
  1347. void CViewContainer::OnBroadcast(const SResourceMapMessage& mesg)
  1348. {
  1349.     if (mesg.rsrcMap == mRsrcMap) {
  1350.         if (mesg.message == kSetResourceID && mesg.oldRsrc.id == mRsrcID) {
  1351.             sContainers.erase(SResourceID(mType, mRsrcID));
  1352.  
  1353.             mRsrcID = mesg.newRsrc.id;
  1354.  
  1355.             sContainers.insert(ContainerEntry(SResourceID(mType, mRsrcID), this));
  1356.         }
  1357.     }
  1358. }
  1359.  
  1360.  
  1361. //---------------------------------------------------------------
  1362. //
  1363. // CViewContainer::OnKeyDown
  1364. //
  1365. //---------------------------------------------------------------
  1366. bool CViewContainer::OnKeyDown(const TKeyEvent& event)
  1367. {
  1368.     bool handled = true;
  1369.     
  1370.     char ch   = event.GetChar();
  1371.     short key = event.GetKey();
  1372.     
  1373.     if (ch == kLeftArrowChar || ch == kRightArrowChar || ch == kUpArrowChar || ch == kDownArrowChar)
  1374.         this->NudgePanes(ch);
  1375.         
  1376.     else {
  1377.         if (ch == kBackspaceChar)
  1378.             key = kClearKey;
  1379.             
  1380.         switch (key) {
  1381.             case kClearKey:
  1382.                 if (this->HasSelection())    
  1383.                     this->OnMenuCommand(kClearCmd);
  1384.                 break;
  1385.                 
  1386.             case kF2Key:
  1387.                 if (this->HasSelection())    
  1388.                     this->OnMenuCommand(kCutCmd);
  1389.                 break;
  1390.                 
  1391.             case kF3Key:
  1392.                 if (this->HasSelection())    
  1393.                     this->OnMenuCommand(kCopyCmd);
  1394.                 break;
  1395.                 
  1396.             case kF4Key:
  1397.                 if (this->CanPaste())    
  1398.                     this->OnMenuCommand(kPasteCmd);
  1399.                 break;
  1400.                 
  1401.             default:
  1402.                 handled = false;
  1403.         }
  1404.     }
  1405.         
  1406.     return handled;
  1407. }
  1408.  
  1409.  
  1410. //---------------------------------------------------------------
  1411. //
  1412. // CViewContainer::OnMenuCommand
  1413. //
  1414. //---------------------------------------------------------------
  1415. bool CViewContainer::OnMenuCommand(const MenuCommand& cmd)
  1416. {
  1417.     bool handled = true;
  1418.     
  1419.     TCommand* command = nil;
  1420.     
  1421.     if (cmd == kCutCmd && this->HasSelection()) {
  1422.         command = new CCutPanesCommand(this);
  1423.         command->Post();
  1424.         
  1425.     } else if (cmd == kCopyCmd && this->HasSelection()) {
  1426.         command = new CCopyPanesCommand(this);
  1427.         command->Post();
  1428.         
  1429.     } else if (cmd == kPasteCmd && this->CanPaste()) {
  1430.         command = new CPastePanesCommand(this, this->GetPasteView());
  1431.         command->Post();
  1432.         
  1433.     } else if (cmd == kClearCmd && this->HasSelection()) {
  1434.         command = new CDeletePanesCommand(this);
  1435.         command->Post();
  1436.         
  1437.     } else if (cmd == kDuplicateCmd && this->CanDuplicate()) {
  1438.         command = new CDuplicatePanesCommand(this);
  1439.         command->Post();
  1440.         
  1441.     } else if (cmd == kAlignLeftCmd) {
  1442.         command = new CAlignLeftCommand(this);
  1443.         command->Post();
  1444.         
  1445.     } else if (cmd == kAlignRightCmd) {
  1446.         command = new CAlignRightCommand(this);
  1447.         command->Post();
  1448.         
  1449.     } else if (cmd == kAlignTopCmd) {
  1450.         command = new CAlignTopCommand(this);
  1451.         command->Post();
  1452.         
  1453.     } else if (cmd == kAlignBottomCmd) {
  1454.         command = new CAlignBottomCommand(this);
  1455.         command->Post();
  1456.         
  1457.     } else if (cmd == kSnapToGridCmd) {
  1458.         mSnapToGrid = !mSnapToGrid;
  1459.         this->UpdateResource();
  1460.         
  1461.     } else if (cmd == kEditGridCmd) {
  1462.         if (CGridSizeDialog::Pose(&mGridSize)) {
  1463.             if (mShowGrid)
  1464.                 this->Invalidate();
  1465.             this->UpdateResource();
  1466.         }
  1467.         
  1468.     } else if (cmd == kShowGridCmd) {
  1469.         mShowGrid = !mShowGrid;
  1470.         this->Invalidate();
  1471.         this->UpdateResource();
  1472.         
  1473.     } else if (cmd == kShowPaneEdgesCmd) {
  1474.         mShowPaneEdges = !mShowPaneEdges;
  1475.         this->AddPaneEdgeAdorners();
  1476.         this->UpdateResource();
  1477.         
  1478.     } else if (cmd == kShowPaneNamesCmd) {
  1479.         mShowPaneNames = !mShowPaneNames;
  1480.         this->AddPaneNameAdorners();
  1481.         this->UpdateResource();
  1482.         
  1483.     } else if (cmd == kShowClassNamesCmd) {
  1484.         mShowClassNames = !mShowClassNames;
  1485.         this->AddClassNameAdorners();
  1486.         this->UpdateResource();
  1487.         
  1488.     } else
  1489.         handled = false;
  1490.     
  1491.     return handled;
  1492. }
  1493.  
  1494.         
  1495. //---------------------------------------------------------------
  1496. //
  1497. // CViewContainer::OnCommandStatus
  1498. //
  1499. //---------------------------------------------------------------
  1500. bool CViewContainer::OnCommandStatus(const MenuCommand& command, SCommandStatus& status)
  1501. {
  1502.     bool handled = true;
  1503.     
  1504.     if (command == kCutCmd) {
  1505.         status.enabled = this->HasSelection();
  1506.         
  1507.     } else if (command == kCopyCmd) {
  1508.         status.enabled = this->HasSelection();
  1509.         
  1510.     } else if (command == kPasteCmd) {
  1511.         status.enabled = this->CanPaste();
  1512.         
  1513.     } else if (command == kClearCmd) {
  1514.         status.enabled = this->HasSelection();
  1515.         
  1516.     } else if (command == kDuplicateCmd) {
  1517.         status.enabled = this->CanDuplicate();
  1518.         
  1519.     } else if (command == kAlignLeftCmd) {
  1520.         status.enabled = this->HasMoreThanOneSelection();
  1521.         
  1522.     } else if (command == kAlignRightCmd) {
  1523.         status.enabled = this->HasMoreThanOneSelection();
  1524.         
  1525.     } else if (command == kAlignTopCmd) {
  1526.         status.enabled = this->HasMoreThanOneSelection();
  1527.         
  1528.     } else if (command == kAlignBottomCmd) {
  1529.         status.enabled = this->HasMoreThanOneSelection();
  1530.         
  1531.     } else if (command == kSnapToGridCmd) {
  1532.         status.enabled = true;
  1533.         if (mSnapToGrid)
  1534.             status.name = LoadIndString(258, 1);
  1535.         else
  1536.             status.name = LoadIndString(258, 2);
  1537.         
  1538.     } else if (command == kEditGridCmd) {
  1539.         status.enabled = true;
  1540.         
  1541.     } else if (command == kShowGridCmd) {
  1542.         status.enabled = true;
  1543.         if (mShowGrid)
  1544.             status.name = LoadIndString(258, 3);        
  1545.         else
  1546.             status.name = LoadIndString(258, 4);
  1547.         
  1548.     } else if (command == kShowPaneEdgesCmd) {
  1549.         status.enabled = true;
  1550.         if (mShowPaneEdges)
  1551.             status.name = LoadIndString(258, 5);        
  1552.         else
  1553.             status.name = LoadIndString(258, 6);
  1554.         
  1555.     } else if (command == kShowPaneNamesCmd) {
  1556.         status.enabled = true;
  1557.         if (mShowPaneNames)
  1558.             status.name = LoadIndString(258, 7);
  1559.         else
  1560.             status.name = LoadIndString(258, 8);
  1561.         
  1562.     } else if (command == kShowClassNamesCmd) {
  1563.         status.enabled = true;
  1564.         if (mShowClassNames)
  1565.             status.name = LoadIndString(258, 9);        
  1566.         else
  1567.             status.name = LoadIndString(258, 10);
  1568.         
  1569.     } else
  1570.         handled = false;
  1571.     
  1572.     return handled;
  1573. }
  1574.  
  1575. #pragma mark ハ
  1576.  
  1577. //---------------------------------------------------------------
  1578. //
  1579. // CViewContainer::FindDropTarget
  1580. //
  1581. //---------------------------------------------------------------
  1582. TView* CViewContainer::FindDropTarget(const TDragSession& session)
  1583. {
  1584.     // Find the mouse position.
  1585.     TPoint mouse = session.GetMouse();
  1586.     mouse = this->GlobalToPort(mouse);
  1587.     mouse = this->PortToLocal(mouse);
  1588.     
  1589.     // Find the view the mouse is over.
  1590.     TView* view = this->FindView(mouse);
  1591.     
  1592.     // If we're dragging the pane within the source window don't
  1593.     // drop the pane inside a selected view (this would lead to
  1594.     // some bad craziness because we're dragging the selected panes).
  1595.     if (view != nil && msSourceTarget == this) {
  1596.         while (view != this && this->InSelection(view))
  1597.             view = view->GetSuperView();
  1598.     }
  1599.  
  1600.     // If the target is the container we need to check the superView.
  1601.     // If it's a CViewWindow the container can only have one subPane.
  1602.     if (view == this) {
  1603.         if (dynamic_cast<CViewWindow*>(this->GetSuperView()) != nil) {
  1604.             if (session.GetItemCount() > 1)
  1605.                 view = nil;
  1606.  
  1607.             else if (mSubPanes->size() == 1) {
  1608.                 ItemReference item = session.GetItemReference(0);
  1609.                 TPane* pane = reinterpret_cast<TPane*>(item);
  1610.                 if (pane != mSubPanes->front())
  1611.                     view = nil;
  1612.             }
  1613.         }
  1614.     }
  1615.                 
  1616.     return view;
  1617. }
  1618.  
  1619.  
  1620. //---------------------------------------------------------------
  1621. //
  1622. // CViewContainer::InSelection
  1623. //
  1624. //---------------------------------------------------------------
  1625. bool CViewContainer::InSelection(TPane* pane) const
  1626. {
  1627.     ASSERT(pane != nil);
  1628.     
  1629.     bool in = this->IsSelected(pane);
  1630.     
  1631.     if (!in) {
  1632.         TView* view = pane->GetSuperView();
  1633.         while (view != this && !in) {
  1634.             in = this->IsSelected(view);
  1635.             view = view->GetSuperView();
  1636.         }
  1637.     }
  1638.     
  1639.     return in;
  1640. }
  1641.  
  1642.  
  1643. //---------------------------------------------------------------
  1644. //
  1645. // CViewContainer::CanDuplicate
  1646. //
  1647. //---------------------------------------------------------------
  1648. bool CViewContainer::CanDuplicate() const
  1649. {
  1650.     bool can = this->HasSelection();
  1651.     
  1652.     if (can && dynamic_cast<CViewWindow*>(this->GetSuperView()) != nil) {
  1653.         TPane* pane = mSubPanes->front();
  1654.         if (this->IsSelected(pane))
  1655.             can = false;
  1656.     }
  1657.     
  1658.     return can;
  1659. }
  1660.  
  1661.  
  1662. //---------------------------------------------------------------
  1663. //
  1664. // CViewContainer::CanPaste
  1665. //
  1666. //---------------------------------------------------------------
  1667. bool CViewContainer::CanPaste() const
  1668. {
  1669.     return ::InScrap('View') && this->GetPasteView() != nil;
  1670. }
  1671.  
  1672.  
  1673. //---------------------------------------------------------------
  1674. //
  1675. // CViewContainer::GetPasteView
  1676. //
  1677. //---------------------------------------------------------------
  1678. TView* CViewContainer::GetPasteView() const
  1679. {
  1680.     TView* view = nil;
  1681.     
  1682.     if (dynamic_cast<CViewWindow*>(this->GetSuperView()) == nil)
  1683.         view = const_cast<CViewContainer*>(this);
  1684.         
  1685.     else if (mSubPanes->size() == 0) {
  1686.         if (::InScrap('View')) {
  1687.             THandle data = ::GetScrap('View');
  1688.             TInHandleStream stream(data);
  1689.             
  1690.             SResource rsrc;
  1691.             stream >> rsrc;
  1692.  
  1693.             if (stream.AtEnd()) 
  1694.                 view = const_cast<CViewContainer*>(this);
  1695.         }
  1696.     
  1697.     } else {
  1698.         TPane* pane = mSubPanes->front();
  1699.         view = dynamic_cast<TView*>(pane);
  1700.     }
  1701.     
  1702.     return view;
  1703. }
  1704.  
  1705.  
  1706. //---------------------------------------------------------------
  1707. //
  1708. // CViewContainer::NudgePanes
  1709. //
  1710. //---------------------------------------------------------------
  1711. void CViewContainer::NudgePanes(char key)
  1712. {
  1713.     if (this->HasSelection()) {
  1714.         CNudgePaneCommand* command = dynamic_cast<CNudgePaneCommand*>(TUndoMgr::GetContext()->GetUndoCommand());
  1715.             
  1716.         if (command == nil || !command->CanNudge(this, key)) {
  1717.             command = new CNudgePaneCommand(this, key);
  1718.             command->Post();
  1719.         }
  1720.  
  1721.         command->Nudge();
  1722.         
  1723.         this->UpdateResource();
  1724.     }
  1725. }
  1726.  
  1727.  
  1728. //---------------------------------------------------------------
  1729. //
  1730. // CViewContainer::ParentIsSelected
  1731. //
  1732. //---------------------------------------------------------------
  1733. bool CViewContainer::ParentIsSelected(TPane* pane) const
  1734. {
  1735.     ASSERT(pane != nil);
  1736.     
  1737.     bool selected = false;
  1738.     
  1739.     TView* super = pane->GetSuperView();
  1740.     while (super != nil && !selected) {
  1741.         selected = this->IsSelected(super);
  1742.         
  1743.         super = super->GetSuperView();
  1744.     }
  1745.     
  1746.     return selected;
  1747. }
  1748.  
  1749.  
  1750. //---------------------------------------------------------------
  1751. //
  1752. // CViewContainer::DoSelect
  1753. //
  1754. //---------------------------------------------------------------
  1755. void CViewContainer::DoSelect(TPane* pane)
  1756. {
  1757.     ASSERT(pane != nil);
  1758.     ASSERT(pane != this);
  1759.     ASSERT(!this->IsSelected(pane));
  1760.     
  1761.     pane->AddAdorner(new CHandleAdorner); 
  1762.  
  1763.     if (TView* view = dynamic_cast<TView*>(pane)) {
  1764.         TSubPaneIterator iter = view->begin(kRecursive);
  1765.         while (iter != view->end()) {
  1766.             TPane* subPane = *iter;
  1767.             ++iter;
  1768.             
  1769.             if (this->IsSelected(subPane))
  1770.                 this->DoDeselect(subPane);
  1771.         }
  1772.     }
  1773. }
  1774.  
  1775.  
  1776. //---------------------------------------------------------------
  1777. //
  1778. // CViewContainer::DoDeselect
  1779. //
  1780. //---------------------------------------------------------------
  1781. void CViewContainer::DoDeselect(TPane* pane)
  1782. {
  1783.     ASSERT(pane != nil);
  1784.     ASSERT(pane != this);
  1785.     ASSERT(this->IsSubPane(pane));
  1786.     ASSERT(this->IsSelected(pane));
  1787.     
  1788.     TAdorner* adorner = pane->FindAdorner("CHandleAdorner");
  1789.     delete adorner;
  1790. }
  1791.  
  1792.  
  1793. //---------------------------------------------------------------
  1794. //
  1795. // CViewContainer::DoDragWindow
  1796. //
  1797. //---------------------------------------------------------------
  1798. void CViewContainer::DoDragWindow(const TPoint& globalPos)
  1799. {
  1800.     GrafPtr port;
  1801.     GetWMgrPort(&port);
  1802.     
  1803.     TSetPort setPort(port);
  1804.     
  1805.     TRect extent = this->GetExtent();
  1806.     extent = this->LocalToPort(extent);
  1807.     extent = this->PortToGlobal(extent);
  1808.     TRegion dragRgn(extent);
  1809.             
  1810.     TRegion grayRgn = GetGrayRgn();
  1811.     TRect limitRect = grayRgn.GetEnclosingRect();
  1812.     limitRect.Inset(4, 4);
  1813.     
  1814.     TSetClip clip(grayRgn);
  1815.     
  1816.     long delta = DragGrayRgn(dragRgn, globalPos, limitRect, limitRect, noConstraint, nil);
  1817.     short dx = LoWord(delta);
  1818.     short dy = HiWord(delta);
  1819.     
  1820.     if (dx != 0 || dy != 0) {
  1821.         TView* topView = this->GetTopView();
  1822.         TWindow* window = dynamic_cast<TWindow*>(topView);
  1823.                 
  1824.         TPoint newLoc = window->GetLocation() + TPoint(dx, dy);
  1825.         window->SetLocation(newLoc);
  1826.     }
  1827. }
  1828.  
  1829.  
  1830. //---------------------------------------------------------------
  1831. //
  1832. // CViewContainer::DecoratePane
  1833. //
  1834. //---------------------------------------------------------------
  1835. void CViewContainer::DecoratePane(TPane* pane, bool add)
  1836. {
  1837.     ASSERT(pane != nil);
  1838.     
  1839.     if (add) {    
  1840.         if (mShowPaneEdges && pane->FindAdorner("COutlineAdorner") == nil)
  1841.             pane->AddAdorner(new COutlineAdorner); 
  1842.         
  1843.         if (mShowPaneNames && pane->FindAdorner("CPaneNameAdorner") == nil)
  1844.             pane->AddAdorner(new CPaneNameAdorner); 
  1845.         
  1846.         if (mShowClassNames && pane->FindAdorner("CClassNameAdorner") == nil)
  1847.             pane->AddAdorner(new CClassNameAdorner); 
  1848.         
  1849.     } else {
  1850.         TAdorner* adorner = pane->FindAdorner("CHandleAdorner");
  1851.         delete adorner;
  1852.  
  1853.         adorner = pane->FindAdorner("COutlineAdorner");
  1854.         delete adorner;
  1855.         
  1856.         adorner = pane->FindAdorner("CPaneNameAdorner");
  1857.         delete adorner;
  1858.         
  1859.         adorner = pane->FindAdorner("CClassNameAdorner");
  1860.         delete adorner;
  1861.     }
  1862.     
  1863.     if (TView* view = dynamic_cast<TView*>(pane)) {
  1864.         TSubPaneIterator iter = view->begin();
  1865.         while (iter != view->end()) {
  1866.             TPane* subPane = *iter;
  1867.             ++iter;
  1868.             
  1869.             this->DecoratePane(subPane, add);
  1870.         }
  1871.     }
  1872. }
  1873.  
  1874.  
  1875. //---------------------------------------------------------------
  1876. //
  1877. // CViewContainer::AddPaneEdgeAdorners
  1878. //
  1879. //---------------------------------------------------------------
  1880. void CViewContainer::AddPaneEdgeAdorners()
  1881. {
  1882.     TSubPaneIterator iter = this->begin(kRecursive);
  1883.     while (iter != this->end()) {
  1884.         TPane* subPane = *iter;
  1885.         ++iter;
  1886.         
  1887.         if (mShowPaneEdges) {
  1888.             if (!subPane->FindAdorner("COutlineAdorner"))
  1889.                 subPane->AddAdorner(new COutlineAdorner); 
  1890.             
  1891.         } else {
  1892.             TAdorner* adorner = subPane->FindAdorner("COutlineAdorner");
  1893.             delete adorner;
  1894.         }
  1895.     }
  1896. }
  1897.  
  1898.  
  1899. //---------------------------------------------------------------
  1900. //
  1901. // CViewContainer::AddPaneNameAdorners
  1902. //
  1903. //---------------------------------------------------------------
  1904. void CViewContainer::AddPaneNameAdorners()
  1905. {
  1906.     TSubPaneIterator iter = this->begin(kRecursive);
  1907.     while (iter != this->end()) {
  1908.         TPane* subPane = *iter;
  1909.         ++iter;
  1910.         
  1911.         if (mShowPaneNames) {
  1912.             if (!subPane->FindAdorner("CPaneNameAdorner"))
  1913.                 subPane->AddAdorner(new CPaneNameAdorner); 
  1914.             
  1915.         } else {
  1916.             TAdorner* adorner = subPane->FindAdorner("CPaneNameAdorner");
  1917.             delete adorner;
  1918.         }
  1919.     }
  1920. }
  1921.  
  1922.  
  1923. //---------------------------------------------------------------
  1924. //
  1925. // CViewContainer::AddClassNameAdorners
  1926. //
  1927. //---------------------------------------------------------------
  1928. void CViewContainer::AddClassNameAdorners()
  1929. {
  1930.     TSubPaneIterator iter = this->begin(kRecursive);
  1931.     while (iter != this->end()) {
  1932.         TPane* subPane = *iter;
  1933.         ++iter;
  1934.         
  1935.         if (mShowClassNames) {
  1936.             if (!subPane->FindAdorner("CClassNameAdorner"))
  1937.                 subPane->AddAdorner(new CClassNameAdorner); 
  1938.             
  1939.         } else {
  1940.             TAdorner* adorner = subPane->FindAdorner("CClassNameAdorner");
  1941.             delete adorner;
  1942.         }
  1943.     }
  1944. }
  1945.  
  1946.  
  1947. //---------------------------------------------------------------
  1948. //
  1949. // CViewContainer::CreatePane
  1950. //
  1951. //---------------------------------------------------------------
  1952. TPane* CViewContainer::CreatePane(TInStream& stream, TView* superView) 
  1953. {
  1954.     TPane* pane = nil;
  1955.     
  1956.     long start;
  1957.  
  1958.     try {
  1959.         start = stream.GetPosition();
  1960.         
  1961.         pane = TPane::Create(stream, superView);
  1962.         
  1963.     } catch (const TReanimateException& e) {
  1964.         stream.SetPosition(start);                            // make sure we can restore the stream before asking the user if he wants to retry
  1965.         
  1966.         if (this->AddBaseClass(e.GetClassName()))
  1967.             pane = this->CreatePane(stream, superView);
  1968.         else
  1969.             throw;
  1970.     }
  1971.  
  1972.     return pane;
  1973. }
  1974.  
  1975.  
  1976. //---------------------------------------------------------------
  1977. //
  1978. // CViewContainer::AddBaseClass
  1979. //
  1980. //---------------------------------------------------------------
  1981. bool CViewContainer::AddBaseClass(const string& derivedClass) 
  1982. {
  1983.     bool added = false;
  1984.  
  1985.     if (mDoc != nil) {
  1986.         if (AnswerYes(derivedClass + LoadAppString(" isn't one of the known types. Would you like to define it?"))) {
  1987.             string baseClass;
  1988.             
  1989.             if (GetString(LoadAppString("Base Class"), &baseClass)) {
  1990.                 CCustomClasses* custom = mDoc->GetCustomPanes();
  1991.                 
  1992.                 custom->AddClass(derivedClass, baseClass);
  1993.                 
  1994.                 added = true;
  1995.             }
  1996.         }
  1997.     }
  1998.     
  1999.     return added;
  2000. }
  2001.  
  2002.  
  2003. //---------------------------------------------------------------
  2004. //
  2005. // CViewContainer::ClickedHandle
  2006. //
  2007. //---------------------------------------------------------------
  2008. bool CViewContainer::ClickedHandle(TPane* pane, const TMouseEvent& event)
  2009. {
  2010.     ASSERT(pane != nil);
  2011.     
  2012.     bool handled = false;
  2013.     
  2014.     if (event.WasMouseDown()) {
  2015.         TPoint mouse = event.GetPosition();
  2016.         mouse = this->LocalToPort(mouse);
  2017.         mouse = pane->PortToLocal(mouse);
  2018.         
  2019.         TPoint anchor(-1, -1);
  2020.         TRect extent = pane->GetExtent();
  2021.         
  2022.         TRect handle = extent;                        // top left
  2023.         handle.right  = handle.left + kHandleSize;
  2024.         handle.bottom = handle.top + kHandleSize;    
  2025.         if (handle.Contains(mouse)) {
  2026.             anchor.h = extent.right;
  2027.             anchor.v = extent.bottom;
  2028.         }
  2029.  
  2030.         handle = extent;                            // right top
  2031.         handle.left   = handle.right - kHandleSize;
  2032.         handle.bottom = handle.top + kHandleSize;    
  2033.         if (handle.Contains(mouse)) {
  2034.             anchor.h = extent.left;
  2035.             anchor.v = extent.bottom;
  2036.         }
  2037.  
  2038.         handle = extent;                            // bottom left
  2039.         handle.right = handle.left + kHandleSize;
  2040.         handle.top   = handle.bottom - kHandleSize;    
  2041.         if (handle.Contains(mouse)) {
  2042.             anchor.h = extent.right;
  2043.             anchor.v = extent.top;
  2044.         }
  2045.  
  2046.         handle = extent;                            // right bottom
  2047.         handle.left = handle.right - kHandleSize;
  2048.         handle.top  = handle.bottom - kHandleSize;    
  2049.         if (handle.Contains(mouse)) {
  2050.             anchor.h = extent.left;
  2051.             anchor.v = extent.top;
  2052.         }
  2053.  
  2054.         if (anchor != TPoint(-1, -1)) {
  2055.             TTracker* tracker = new CResizeTracker(pane, anchor, mouse);
  2056.             tracker->Post();
  2057.             
  2058.             handled = true;
  2059.         }
  2060.     }
  2061.         
  2062.     return handled;
  2063. }
  2064.  
  2065.  
  2066.